import sequelize from '@/config/database';
import { getLogger } from '@/utils/logger';
import monitorConfig from '@/config/monitor';

const logger = getLogger('db-monitor');

/**
 * 数据库监控工具
 * 提供对Sequelize和原始数据库查询的性能监控功能
 */
class DbMonitor {
  /**
   * 初始化数据库监控钩子
   */
  public init(): void {
    if (!monitorConfig.database.enabled) {
      logger.info('数据库监控功能已禁用');
      return;
    }
    
    // 安装Sequelize查询拦截器
    this.setupSequelizeHooks();
    
    // 初始化慢查询监控
    this.initSlowQueryMonitoring();
    
    logger.info('数据库监控功能已初始化');
  }
  
  /**
   * 设置Sequelize钩子函数
   */
  private setupSequelizeHooks(): void {
    try {
      // 监控所有查询
      sequelize.addHook('beforeQuery', (options: any) => {
        // 记录查询开始时间
        options._queryStartTime = Date.now();
      });
      
      sequelize.addHook('afterQuery', (options: any) => {
        try {
          if (options._queryStartTime) {
            // 计算查询耗时
            const duration = Date.now() - options._queryStartTime;
            
            // 提取查询类型和表名
            const sql = options.sql || '';
            const queryType = this.extractQueryType(sql);
            const tableName = this.extractTableName(sql, queryType);
            
            // 记录慢查询日志
            if (duration > monitorConfig.database.slowQueryThreshold) {
              logger.warn(`慢查询 (${duration}ms): ${sql}`);
            }
          }
        } catch (error) {
          logger.error('处理查询钩子时出错:', error);
        }
      });
    } catch (error) {
      logger.error('设置Sequelize钩子失败:', error);
    }
  }
  
  /**
   * 初始化慢查询监控
   */
  private initSlowQueryMonitoring(): void {
    // 此处可以添加定期检查数据库慢查询日志的逻辑
    setInterval(async () => {
      try {
        await this.checkDatabaseStatus();
      } catch (error) {
        logger.error('检查数据库状态失败:', error);
      }
    }, monitorConfig.database.collectInterval);
  }
  
  /**
   * 检查数据库状态
   */
  private async checkDatabaseStatus(): Promise<void> {
    try {
      // 查询数据库状态信息
      const [results] = await sequelize.query('SHOW STATUS') as any[];
      
      // 提取关键指标
      const stats: Record<string, number> = {};
      
      for (const row of results) {
        const name = row.Variable_name;
        const value = parseInt(row.Value, 10);
        
        if (!isNaN(value)) {
          stats[name] = value;
        }
      }
      
      // 获取连接相关指标
      if (stats['Max_used_connections'] && stats['max_connections']) {
        const connectionUsage = (stats['Max_used_connections'] / stats['max_connections']) * 100;
        
        // 检查连接使用率是否超过阈值
        if (connectionUsage > monitorConfig.database.maxConnectionsUsageThreshold) {
          logger.warn(`数据库连接使用率过高: ${connectionUsage.toFixed(2)}%`);
        }
      }
      
      // 获取慢查询数量
      if (stats['Slow_queries']) {
        logger.debug(`数据库慢查询数: ${stats['Slow_queries']}`);
      }
    } catch (error) {
      logger.error('查询数据库状态失败:', error);
    }
  }
  
  /**
   * 提取SQL查询类型
   * @param sql SQL语句
   * @returns 查询类型（SELECT, INSERT, UPDATE, DELETE等）
   */
  private extractQueryType(sql: string): string {
    sql = sql.trim().toUpperCase();
    
    if (sql.startsWith('SELECT')) return 'SELECT';
    if (sql.startsWith('INSERT')) return 'INSERT';
    if (sql.startsWith('UPDATE')) return 'UPDATE';
    if (sql.startsWith('DELETE')) return 'DELETE';
    if (sql.startsWith('CREATE')) return 'CREATE';
    if (sql.startsWith('ALTER')) return 'ALTER';
    if (sql.startsWith('DROP')) return 'DROP';
    if (sql.startsWith('TRUNCATE')) return 'TRUNCATE';
    if (sql.startsWith('SHOW')) return 'SHOW';
    
    return 'OTHER';
  }
  
  /**
   * 提取SQL查询的表名
   * @param sql SQL语句
   * @param queryType 查询类型
   * @returns 表名
   */
  private extractTableName(sql: string, queryType: string): string {
    try {
      sql = sql.trim();
      
      switch (queryType) {
        case 'SELECT':
          // 提取FROM子句后的表名
          const fromMatch = sql.match(/FROM\s+`?(\w+)`?/i);
          return fromMatch ? fromMatch[1] : 'unknown';
          
        case 'INSERT':
          // 提取INTO子句后的表名
          const intoMatch = sql.match(/INTO\s+`?(\w+)`?/i);
          return intoMatch ? intoMatch[1] : 'unknown';
          
        case 'UPDATE':
          // 提取UPDATE子句后的表名
          const updateMatch = sql.match(/UPDATE\s+`?(\w+)`?/i);
          return updateMatch ? updateMatch[1] : 'unknown';
          
        case 'DELETE':
          // 提取FROM子句后的表名
          const deleteFromMatch = sql.match(/FROM\s+`?(\w+)`?/i);
          return deleteFromMatch ? deleteFromMatch[1] : 'unknown';
          
        default:
          return 'unknown';
      }
    } catch (error) {
      logger.error('提取表名失败:', error);
      return 'unknown';
    }
  }
  
  /**
   * 监控原生SQL查询
   * @param sql SQL语句
   * @param fn 查询函数
   * @returns 查询结果
   */
  public async monitorQuery<T>(sql: string, fn: () => Promise<T>): Promise<T> {
    const startTime = Date.now();
    try {
      return await fn();
    } finally {
      const duration = Date.now() - startTime;
      const queryType = this.extractQueryType(sql);
      const tableName = this.extractTableName(sql, queryType);
      
      // 记录慢查询日志
      if (duration > monitorConfig.database.slowQueryThreshold) {
        logger.warn(`慢查询 (${duration}ms): ${sql}`);
      }
    }
  }
}

export default new DbMonitor(); 